﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RVBike
{
    class RVGameController : Singleton<RVGameController>
    {
        private RVGameClient _client;
        private RVGameServer _server;

        public RVNetworkEnv.JoinRoomHandlers JoinRoomHandler { get; set; }
        public RVNetworkEnv.LeaveRoomHandlers LeaveRoomHandler { get; set; }
        public RVNetworkEnv.ClientStateChangeHandlers ClientStateChangeHandler { get; set; }
        public RVNetworkEnv.QuitRoomHandlers QuitRoomHandler { get; set; }
        public RVNetworkEnv.GameStartHandlers GameStartHandler { get; set; }
        public RVNetworkEnv.StartPlayHandlers StartPlayingHandler { get; set; }

        public bool Master { get; set; }

        public RVGameController()
        {
            _client = null;
            _server = null;
        }

        private void RegisterCallback()
        {
            // Register callback from client
            _client.JoinRoomHandler += OnReceiveJoinRoom;
            _client.LeaveRoomHandler += OnReceiveLeaveRoom;
            _client.ClientStateChangeHandler += OnReceiveCSChanged;
            _client.QuitRoomHandler += OnReceiveQuitRoom;
            _client.GameStartHandler += OnReceiveGameStart;
            _client.StartPlayingHandler += OnReceiveStartPlaying;
        }

        private void UnregisterCallback()
        {
            // Unregister callback from client
            _client.JoinRoomHandler -= OnReceiveJoinRoom;
            _client.LeaveRoomHandler -= OnReceiveLeaveRoom;
            _client.ClientStateChangeHandler -= OnReceiveCSChanged;
            _client.QuitRoomHandler -= OnReceiveQuitRoom;
            _client.GameStartHandler -= OnReceiveGameStart;
            _client.StartPlayingHandler -= OnReceiveStartPlaying;
        }

        public bool CreateRoom(RVRoom room, string name, string mcastIP)
        {
            if (_server != null)
            {
                System.Diagnostics.Trace.WriteLine("Create room twice!!");
                return false;
            }

            if (_client != null)
            {
                System.Diagnostics.Trace.WriteLine("Cannot create room because you had join other room!!");
                return false;
            }

            _server = new RVGameServer(room, mcastIP);
            _client = new RVGameClient(name, NetworkUtility.MyIP(), mcastIP);
            if (!_client.JoinRoom())
            {
                System.Diagnostics.Trace.WriteLine("Failed to join room, server reject");

                // ... fail to join my room ......
                _client.Close();
                _client = null;

                _server.Close();
                _server = null;

                return false;
            }

            RegisterCallback();

            Master = true;

            return true;
        }

        public bool JoinRoom(string name, string serverIP, string mcastIP)
        {
            if (_server != null)
            {
                System.Diagnostics.Trace.WriteLine("Cannot join room because you had created your room before!!");
                return false;
            }

            if (_client != null)
            {
                System.Diagnostics.Trace.WriteLine("Join room twice");
                return false;
            }

            _client = new RVGameClient(name, serverIP, mcastIP);
            if (!_client.JoinRoom())
            {
                System.Diagnostics.Trace.WriteLine("Failed to join room, server reject");
                _client.Close();
                _client = null;
                return false;
            }

            RegisterCallback();

            Master = false;

            return true;
        }

        public bool LeaveRoom()
        {
            // Sever is host by self
            if (_server != null)
            {
                // Close client of myself
                if (_client == null)
                {
                    System.Diagnostics.Trace.WriteLine("!!! It is bug, open room but not join!!");
                }
                else
                {
                    if (!_client.LeaveRoom())
                    {
                        System.Diagnostics.Trace.WriteLine("Failed to leave room");
                        return false;
                    }

                    UnregisterCallback();

                    _client.Close();
                    _client = null;
                }

                _server.Close();
                _server = null;
                return true;
            }
            else
            {
                if (_client == null)
                {
                    System.Diagnostics.Trace.WriteLine("Failed to leave room : not join room yet");
                    return false;
                }

                UnregisterCallback();

                _client.Close();
                _client = null;
                return true;
            }
        }

        public RVRoom QueryRoomInformation()
        {
            if (_client == null)
            {
                System.Diagnostics.Trace.WriteLine("QueryRoomInformation failed : not join any room yet");
                return null;
            }

            return _client.QueryRoomInfo();
        }

        public bool UpdateState(string state, float mileage, string gps)
        {
            if (_client == null)
            {
                System.Diagnostics.Trace.WriteLine("Update state failed : not join any room yet");
                return false;
            }

            return _client.UpdateInfo(state, mileage, gps);
        }

        public bool SendGameStart()
        {
            if (_client == null)
            {
                System.Diagnostics.Trace.WriteLine("Update state failed : not join any room yet");
                return false;
            }

            return _client.GameStart();
        }

        private void OnReceiveJoinRoom(string name, string ip)
        {
            // notify outside
            if (JoinRoomHandler != null) JoinRoomHandler(name, ip);
        }

        private void OnReceiveLeaveRoom(string ip)
        {
            if (LeaveRoomHandler != null) LeaveRoomHandler(ip);
        }

        private void OnReceiveCSChanged(string ip, float mileage, string state, string gps)
        {
            if (ClientStateChangeHandler != null) ClientStateChangeHandler(ip, mileage, state, gps);
        }

        private void OnReceiveQuitRoom()
        {
            if (QuitRoomHandler != null) QuitRoomHandler();
        }

        private void OnReceiveGameStart()
        {
            if (GameStartHandler != null) GameStartHandler();
        }

        private void OnReceiveStartPlaying()
        {
            if (StartPlayingHandler != null) StartPlayingHandler();
        }
    }
}
